﻿using System;
using System.Security.Cryptography;
using System.Text;
using System.Web.Security;

/// <summary>
/// 提供用户注册、密码验证等功能。
/// </summary>
public class Membership
{
	/// <summary>
	/// 创建用户。
	/// </summary>
	/// <param name="userName">用户名。</param>
	/// <param name="password">密码。</param>
	public static void CreateUser(string userName, string password)
	{
		UserObject user = new UserObject();
		user.Name = userName;
		user.PasswordSalt = GenerateSalt();
		user.PasswordHash = EncodePassword(password, user.PasswordSalt);

		DataAccess.AddUser(user);
	}

	/// <summary>
	/// 用户登录。完成验证密码、设置用户凭证Cookie，并完成重定向。
	/// </summary>
	/// <param name="userName">用户名。</param>
	/// <param name="password">密码。</param>
	/// <param name="rememberMe">是否“记住我”。</param>
	/// <exception cref="ArgumentException">当userName所指定的用户不存在，或password所指定的密码错误时引发。</exception>
	public static void Login(string userName, string password, bool rememberMe)
	{
		// 获取用户。
		UserObject user = DataAccess.GetUserByName(userName);
		if(user == null)
			throw new ArgumentException("用户不存在！", "UserName");

		// 检查密码是否正确。
		string pwdHash = EncodePassword(password, user.PasswordSalt);
		if(pwdHash != user.PasswordHash)
			throw new ArgumentException("密码错误！", "Password");

		// 设置安全Cookie并进行重定向。
		FormsAuthentication.RedirectFromLoginPage(userName, rememberMe);
	}

	/// <summary>
	/// 用于对密码进行散列的算法名字。
	/// </summary>
	public const string PasswordHashAlgorithmName = "SHA1";

	/// <summary>
	/// 使用给定的Salt值对密码进行散列。
	/// </summary>
	/// <param name="password">密码。</param>
	/// <param name="salt">Salt值。</param>
	/// <returns>经过散列的密码。</returns>
	static string EncodePassword(string password, string salt)
	{
		byte[] src = Encoding.Unicode.GetBytes(password);
		byte[] saltbuf = Convert.FromBase64String(salt);
		byte[] dst = new byte[saltbuf.Length + src.Length];
		byte[] inArray = null;
		Buffer.BlockCopy(saltbuf, 0, dst, 0, saltbuf.Length);
		Buffer.BlockCopy(src, 0, dst, saltbuf.Length, src.Length);

		HashAlgorithm algorithm = HashAlgorithm.Create(PasswordHashAlgorithmName);
		inArray = algorithm.ComputeHash(dst);

		return Convert.ToBase64String(inArray);
	}

	/// <summary>
	/// 生成随机的Salt值。
	/// </summary>
	/// <returns>表示Salt值的base64字符串。</returns>
	static string GenerateSalt()
	{
		byte[] data = new byte[0x10];
		new RNGCryptoServiceProvider().GetBytes(data);
		return Convert.ToBase64String(data);
	}
}
